#include <iostream>
#include <cstdlib>
#include <cstring>
#include <stack>
#include <queue>
#define maxnum 1000
using namespace std;
typedef struct node
{
    int x,y;//地图坐标,从（1，1）开始
}mapnode;

int flag=0;//判断能否到终点
int m, n;//地图的行m与列n
int **map;//地图信息,0可以走，1不能走
int **visited;//访问信息，0表示未访问，1表示已经访问过
int minsize;//最短路径长度
stack<mapnode> s,mins;//深度遍历求所有路径，存路径和最短路径的栈
queue<mapnode> q;
mapnode in, out,**pre;//起点、终点、当前点的前一个点 的坐标
int movex[4]={0,1,0,-1};
int movey[4]={-1,0,1,0};//对应左、下、右、上移动

void createmap(int m, int n);//输入地图信息,创建访问信息
void visited0();// 清空访问信息
void deleteinfo(int m, int n);//删除申请的空间
void outputmap(int m, int n); // 输出地图
void outputroad(stack<mapnode> s1, int n); ////输出路径（坐标）,从栈底到栈顶的输出，n为控制符,传递形参，不影响实参
void outputvisited(int m, int n);// 输出访问数组，检查用
int pass(mapnode p);// 检查点是否可以走
int BFSminroad(queue<mapnode> &q);//广度遍历，非递归求最短路径,用visited存路径长度
void DFSallroad(stack<mapnode> &s); // 深度遍历，递归查找所有路径
void DFS(stack<mapnode> &s); // 深度遍历，递归

void createmap(int m, int n) // 输入地图信息,创建访问信息
{
    int i, j;
    //mapnode test;
    map = new int *[m+1];//m+1行
    visited = new int *[m + 1];
    //map = (int **)calloc(m+1,sizeof(int *));
    //visited = (int **)calloc(m + 1, sizeof(int *));
    for (i = 0; i <= m; i++)
    {
        map[i] = new int[n+1];// m+1行n+1列
        visited[i] = new int[n+1];
        //map[i] = (int *)calloc(n + 1, sizeof(int));
        //visited[i] = (int *)calloc(n + 1, sizeof(int)); 
    }
    for (i = 1; i <= m; i++)
      for (j = 1; j <= n; j++)
      {
        cin >> map[i][j];//输入地图信息
      }
    for (i = 1; i <= m; i++)//初始化访问数组为0 
     for (j = 1; j <= n; j++)
         visited[i][j] = 0;
}

void visited0()// 清空访问信息
{
    int i, j;
    for (i = 1; i <= m; i++)//初始化访问数组为0 
     for (j = 1; j <= n; j++)
         visited[i][j] = 0;
}

void deleteinfo(int m,int n)
{//删除申请的空间
    int i;
    for (i = 0; i <= m; i++)//从0开始，m+1个全释放
    {
        delete[] map[i];//释放一级指针
        delete[] visited[i];
        //delete[] pre[i];
        //free(map[i]);
        //free(visited[i]);
    }
    delete[] map;//释放二级指针
    delete[] visited;
    //delete[] pre;
    //free(map);
    //free(visited);
}

void outputroad(stack<mapnode> s1,int n)//传递形参，不影响实参
{//输出路径（坐标）,从栈底到栈顶的输出，n为控制符
    stack<mapnode> s2;
    if(n==1)//n为控制符，n=1表示结合DFSallroad使用，每次输出时比较路径长度
    {
        if(s.size()-1<(unsigned int)minsize)//minsize>0,可强制转化为无符号数
        {
         mins = s;
         minsize = s.size()-1;
        }
    }//n！=1时，单纯作为输出路径函数使用，不比较最短路径长度,不更新最短路径
    while(!s1.empty())//将栈s1翻转存到栈s2中
    {//实现从栈底到栈顶的输出
     s2.push(s1.top());
     s1.pop();
    }
    while(!s2.empty())
    {
        cout << '(' << s2.top().x << ',' << s2.top().y << ')';
        s2.pop();
        if (!s2.empty())
        {
         cout << "->";
        }
    }
    cout << endl;
}

void outputmap(int m,int n)//输出地图
{
    cout << endl;
    int i, j;
    for (i = 1; i <= m; i++)
    {
        for (j = 1; j <= n; j++)
        {
            if(map[i][j]<2)
                cout << map[i][j] << ' ';
            else if(map[i][j]==2)//起点
                cout << "*"<<' ';
            else if(map[i][j]==3)//终点
                cout << "#"<<' ';
        }
        cout << endl;
    }
    cout << endl;
    cout << "注：地图坐标从(1,1)开始" << endl;
    cout << endl;
}

void outputvisited(int m,int n)//输出访问数组，检查用
{
    int i, j;
    cout << endl;
    for (i = 1; i <= m; i++)
    {
        for (j = 1; j <= n; j++)
        {
            cout << visited[i][j] << ' '; 
        }
        cout << endl;
    }
    cout << endl;
}

int pass(mapnode  p)//检查点是否可以走
{
    if (p.x<1 || p.x>m)//x坐标超出迷宫范围
    {
		return 0;
	}
	else if (p.y<1 || p.y>n)//y坐标超出迷宫范围
    {	
		return 0;
	}
	else if (!(visited[p.x][p.y] == 0))//已经走过该点
    {
		return 0;
	}
	else if (map[p.x][p.y] == 1)//该点是障碍
    {
		return 0;
	}
	else
        return 1; //可以走
}

int BFSminroad(queue<mapnode> &q)
{//广度遍历，非递归求最短路径,用visited存路径长度
    int i, j, temp;
    visited0();//清空访问信息
    pre = new mapnode *[m + 1]; // m+1行
    for (i = 0; i <= m; i++)
    {
        pre[i] = new mapnode[n+1];// m+1行n+1列 
    }
    q.push(out);//终点入队列，从终点往起点找路径
    pre[out.x][out.y].x= 0;
    pre[out.x][out.y].y= 0;//终点的前点设为（0，0）
    mapnode p,next;
    while(!q.empty())
    {
        p = q.front();//取队列首元素
        q.pop();// 队列首元素出队列
        if(p.x==in.x&&p.y==in.y)//队首为起点时查找结束
        {//能到达终点,输出路径和长度
            flag = 1;//能到达终点标志
            i = in.x;
            j = in.y; 
            while (i != 0 && j != 0)
            {
                printf("(%d, %d)", i, j);
                temp = i;
                i = pre[i][j].x;
                j = pre[temp][j].y;
                if (i != 0 && j != 0)
                {
                    cout << "->";
                }
            }
            cout << endl;
            cout << "最短路径长度为：" << visited[in.x][in.y] << endl;
            for (i = 0; i <= m; i++)//从0开始，m+1个全释放
            {
                delete[] pre[i];
            }
            delete[] pre;
            while(!q.empty())//清空队列 
            {
            	q.pop();
			}
            return 1;
        }
        for (i = 0; i < 4; i++)//循环遍历探测周围4个方向上的点
        {
            next.x = p.x + movex[i];
            next.y = p.y + movey[i];
            //printf("\n%d:%d,%d\n", i, next.x, next.y);
            if (pass(next)&&(next.x!=out.x||next.y!=out.y))// next为p的下一个点
            {
                visited[next.x][next.y] = visited[p.x][p.y] + 1; // 访问对应点,距离+1
                q.push(next);
                pre[next.x][next.y].x = p.x;
                pre[next.x][next.y].y = p.y;
            }
        }
    }
    cout << "找不到起点与终点间的路径,故无最短路径"<<endl;//while结束，队列空也没到终点
    for (i = 0; i <= m; i++) // 从0开始，m+1个全释放
    {
        delete[] pre[i];
    }
    delete[] pre;
    while(!q.empty())//清空队列 
    {
        q.pop();
	}
    return 0;
}

void DFSallroad(stack<mapnode> &s)
{
    visited0();
    flag = 0;//重置有通路标志符
    minsize = m * n;
    visited[in.x][in.y] = 1;//访问起点
    s.push(in);//起点入栈
    DFS(s);
}

void DFS(stack<mapnode> &s)
{//深度遍历，递归查找所有路径
    int i;
    mapnode p,next;//p工作点，next为p的下一个点
    p = s.top();//工作点为栈顶元素
    if(p.x==out.x&&p.y==out.y)//栈顶元素为终点
    {//能到达终点
        outputroad(s,1);//输出路径——从栈底到栈顶
        visited[p.x][p.y] = 0;//回退，恢复未访问状态
        s.pop();
        flag = 1;//能到达终点
        return;//找到终点，结束递归
    }
    for (i = 0; i < 4; i++)//循环遍历探测周围4个方向上的点
    {//i的不同，保证递归返回到分叉点时不再选择已选方向
        next.x = p.x + movex[i];
        next.y = p.y + movey[i];
        if(pass(next))//next为p的下一个点
        {//p.y = p.y + movey[i];// p.x = p.x + movex[i];
            visited[next.x][next.y] = 1; //访问对应点
            s.push(next);
            DFS(s);//递归
        }
    }
    s.pop();
    visited[p.x][p.y] = 0;//回退，恢复未访问状态
    if(s.empty())
    {
        if(flag==0)
        {
            cout << "找不到起点与终点间的路径";
        }
        else
        {
            cout << endl
                 << "所有路径已输出。最短路径长度为"<<minsize<<",如下：" << endl;
            outputroad(mins,0);
            while(!mins.empty())//清空最小路径栈
            {
            	mins.pop();
			}
        }
    
    }
}

int main()
{
    int flag2 = 1, flag3 = 1;
    int x;
    char y;
    while(flag2==1)//一级循环
    {
        cout << "请输入迷宫的行数和列数:" << endl;
        cin >> m >> n; // 迷宫第一个点坐标为（1,1）
        cout << "请输入迷宫的信息(0表示可通过,1表示障碍物):" << endl;
        createmap(m, n); // 输入地图信息
        cout << "注：地图坐标从(1,1)开始" << endl;
        cout << "请输入起点和终点:" << endl;
        while(flag3==1)//输入起点终点，二级循环
        {
            cin >> in.x >> in.y;
            cin >> out.x >> out.y;
            if(in.x<1||in.x>m||in.y<1||in.y>n||out.x<1||out.x>m||out.y<1||out.y>n||(in.x==out.x&&in.y==out.y))
            {//起点不能等于终点，起点终点不能为墙
                system("cls");
                cout << "你输入的地图如下" << endl
                     << "0表示可通过,1表示障碍物" << endl;
                outputmap(m, n);
                cout<<"起点终点坐标不符合,请重新输入:"<<endl;
                flag3 = 1;
                continue;//进入下一轮二级循环,重新输入起点终点
            }
            else if (map[in.x][in.y] == 1 || map[out.x][out.y] == 1)
            {
            	system("cls");
                cout << "你输入的地图如下" << endl
                     << "0表示可通过,1表示障碍物" << endl;
                outputmap(m, n);
                cout<<"起点终点坐标不符合,请重新输入:"<<endl;
                flag3 = 1;
                continue;//进入下一轮二级循环,重新输入起点终点
			}
            else
            {
                map[in.x][in.y] = 2;   // 起点
                map[out.x][out.y] = 3; // 终点
            }
            system("cls");
            cout << "你输入的地图如下" << endl
                 << "0表示可通过,1表示障碍物,*为起点，#为终点，" << endl;
            outputmap(m, n);   // 打印地图
            printf("从(%d,%d)到(%d,%d)的一条最短的路径如下:\n",in.x,in.y,out.x,out.y);
            x = BFSminroad(q); // 输出最短路径
            if (x == 1)        // 有通路
            {
                cout << "是否输出所有路径?(Y or N)" << endl;
                cin >> y;
                if (y == 'y' || y == 'Y')
                {
                    system("cls");
                    cout << "你输入的地图如下" << endl
                         << "0表示可通过,1表示障碍物,*为起点，#为终点，" << endl;
                    outputmap(m, n); // 打印地图
                    printf("从(%d,%d)到(%d,%d)的所有路径如下:\n",in.x,in.y,out.x,out.y);
                    DFSallroad(s);// 输出所有路径
                    cout << endl;
                }
                cout << "是否重新输入起点和终点?(Y or N)" << endl;
                cin >> y;
                if (y == 'y' || y == 'Y')
                {
                    map[in.x][in.y] = 0;   // 重置起点
                    map[out.x][out.y] = 0; // 重置终点
                    system("cls");
                    cout << "你输入的地图如下" << endl
                         << "0表示可通过,1表示障碍物" << endl;
                    outputmap(m, n); // 打印地图
                    cout << "请输入起点和终点:" << endl;
                    flag3 = 1;
                    continue;//进入下一轮二级循环,重新输入起点终点
                }
                cout << "是否继续输入新地图?(Y or N)" << endl;
                cin >> y;
                if(y=='y'||y=='Y')
                {
                    deleteinfo(m, n);//释放空间
                    flag2 = 1;
                    system("cls");
                    break;//结束二级循环
                }
                else
                {
                    deleteinfo(m, n);//释放空间
                    flag2 = 0;
                    system("cls");
                    break;//结束二级循环
                }
            }
            else//无通路
            {
                cout << "是否重新输入起点和终点?(Y or N)" << endl;
                cin >> y;
                if (y == 'y' || y == 'Y')
                {
                    map[in.x][in.y] = 0;   // 重置起点
                    map[out.x][out.y] = 0; // 重置终点
                    system("cls");
                    cout << "你输入的地图如下" << endl
                         << "0表示可通过,1表示障碍物" << endl;
                    outputmap(m, n); // 打印地图
                    cout << "请输入起点和终点:" << endl;
                    flag3 = 1;
                    continue;//进入下一轮二级循环,重新输入起点终点
                }
                cout << "是否继续输入新地图?(Y or N)" << endl;
                cin >> y;
                if(y=='y'||y=='Y')
                {
                    deleteinfo(m, n);//释放空间
                    flag2 = 1;
                    system("cls");
                    break;//结束二级循环
                }
                else
                {
                    deleteinfo(m, n);//释放空间
                    flag2 = 0;
                    system("cls");
                    break;//结束二级循环，退出系统
                }
            }  
        }
        
    }
    return 0;
}

/*
test 1:
输入迷宫的行数和列数:
4 4

输入迷宫的信息(0表示可通过,1表示障碍物):
1 0 1 1
1 0 0 0
1 0 1 0
1 0 0 0

输入起点和终点:      
1 2
2 4

查询所有路径

重新输入错误的起点、终点
6 6
2 6

提示起点、终点坐标不符合
重新输入正确的起点、终点
1 2
4 4

选择不重新输入起点和终点，选择重新输入地图

test2:
输入迷宫的行数和列数:
6 6

输入迷宫的信息(0表示可通过,1表示障碍物):
1 0 1 1 1 1
1 0 0 0 0 1
1 0 1 1 0 1
1 0 1 1 0 0 
1 0 1 1 0 1
1 0 0 0 0 1

输入起点和终点:      
1 2
4 6

选择输出所有路径

不再重新输入起点终点，不再重新输入地图

退出系统
*/